/*
 * 2011 Runedev development team
 * http://lazygamerz.org
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser Gereral Public Licence as published by the Free
 * Software Foundation; either version 3 of the Licence, or (at your opinion) any
 * later version.
 *
 * This library is distributed in the hope that it will be usefull, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of merchantability or fitness for a
 * particular purpose. See the GNU Lesser General Public Licence for more details.
 *
 * You should have received a copy of the GNU Lesser General Public Licence along
 * with this library; if not, write to the Free Software Foundation, Inc., 59
 * Temple Place, Suite 330, Boston, Ma 02111-1307 USA.
 *
 * http://www.gnu.org/licenses/lgpl.html (English)
 * http://gugs.sindominio.net/gnu-gpl/lgpl-es.html (Espa�ol)
 *
 */
package org.lazygamerz.scripting.api;

import java.awt.Point;

import org.rsbot.bot.Bot;
import org.rsbot.script.wrappers.RSInterface;
import org.rsbot.script.wrappers.RSInterfaceChild;
import org.rsbot.script.wrappers.RSItem;

/**
 * Game equipment tab.
 * @author Runedev Development Team - version 1.0
 */
public class Equipment {
    private final java.util.Random random = new java.util.Random();

    public static final int slots = 11;
    public static final int iFaceEquipment = 387;
    public static final int helmet = 8;
    public static final int cape = 11;
    public static final int necklace = 14;
    public static final int weapon = 17;
    public static final int body = 20;
    public static final int shield = 23;
    public static final int legs = 26;
    public static final int hands = 29;
    public static final int feet = 32;
    public static final int ring = 35;
    public static final int ammo = 38;

    public Equipment() {
    }

    /**
     * Performs an action on a given equipped item ID by clicking it in the
     * equipment tab. Written by Garrett.
     *
     * @param id    The ID of the item to look for.
     * @param act   The menu action to click.
     * @return      <tt>true</tt> if the action was clicked; otherwise false.
     */
    public boolean clickItem(int id, String act) {
        if (Bot.game.getCurrentTab() != Game.tabEquipment) {
            Bot.game.openTab(Game.tabEquipment);
            Bot.game.wait(random(900, 1500));
        }
        RSInterfaceChild[] equip = getInterface().getChildren();
        for (int i = 0; i < 11; i++) {
            if (equip[i * 3 + 8].getChildID() == id) {
                int x = equip[i * 3 + 8].getAbsoluteX() + 2;
                int y = equip[i * 3 + 8].getAbsoluteY() + 2;
                int width = equip[i * 3 + 8].getWidth() - 2;
                int height = equip[i * 3 + 8].getHeight() - 2;
                Bot.mouse.move(new Point(random(x, x + width), random(y, y + height)));
                Bot.game.wait(random(50, 100));
                return Bot.menu.action(act);
            }
        }
        return false;
    }

    /**
     * Gets the equipment array.
     *
     * @return array        containing all equipped items
     */
    public RSItem[] getArray() {
        RSInterfaceChild[] equip = getInterface().getChildren();
        final RSItem[] items = new RSItem[slots];
        for (int i = 0; i < items.length; i++) {
            items[i] = new RSItem(equip[i * 3 + 8]);
        }
        return items;
    }

    /**
     * Gets the cached equipment array (i.e. does not open the interface).
     *
     * @return The items equipped as seen when the equipment tab was last
     *         opened.
     */
    public RSItem[] getCachedItems() {
        final RSInterface equipment = Bot.iface.get(iFaceEquipment);
        final RSInterfaceChild[] components = equipment.getChildren();
        final RSItem[] items = new RSItem[slots];
        for (int i = 0; i < items.length; i++) {
            items[i] = new RSItem(components[i * 3 + 8]);
        }
        return items;
    }

    /**
     * Returns the number of items equipped excluding stack sizes.
     *
     * @return Amount       of items currently equipped.
     */
    public int getCount() {
        return slots - getCount(-1);
    }

    /**
     * Returns the number of items matching a given ID equipped excluding stack
     * sizes.
     *
     * @param id        The item ID to count. Same as the equipment/item id in the
     *                  inventory.
     * @return Amount   of specified item currently equipped.
     * @see #getArray()
     */
    public int getCount(int id) {
        int count = 0;
        for (final RSItem item : getArray()) {
            if (item.getID() == id) {
                count++;
            }
        }
        return count;
    }

    /**
     * Gets the equipment interface.
     *
     * @return      the equipment interface
     * @see         #setEnforceTabFocus(boolean)
     */
    public RSInterface getInterface() {
        /* Tab needs to be open for it to update it's content -.- */
        if (Bot.game.openTabs && Bot.game.getCurrentTab() != Game.tabEquipment) {
            if (Bot.bank.isOpen()) {
                Bot.bank.close();
            }
            Bot.game.openTab(Game.tabEquipment);
            Bot.game.wait(random(900, 1500));
        }
        return Bot.iface.get(iFaceEquipment);
    }

    public int[] getStackArray() {
        return new int[0];
    }

    /**
     * Gets the equipment item at a given index.
     *
     * @param index The item index.
     * @return The equipped item.
     */
    public RSItem getItem(final int index) {
        return new RSItem(getInterface().getChildren()[index]);
    }

    /**
     * Gets the equipment array.
     *
     * @return An array containing all equipped items
     */
    public RSItem[] getItems() {
        RSInterfaceChild[] equip = getInterface().getChildren();
        RSItem[] items = new RSItem[slots];
        for (int i = 0; i < items.length; i++) {
            items[i] = new RSItem(equip[i * 3 + 8]);
        }
        return items;
    }

    /**
     * Checks whether the player has all of the given items equipped.
     *
     * @param id                The item ID to check for. Same as the equipment/
     *                          item id in the inventory.
     * @return <tt>true</tt>    if specified item is currently equipped; otherwise
     *                          <tt>false</tt>.
     * @see #getArray()
     */
    public boolean contains(int... ids) {
        RSItem[] equipID = getArray();
        int count = 0;
        for (int item : ids) {
            for (RSItem equip : equipID) {
                if (equip.getID() == item) {
                    count++;
                    break;
                }
            }
        }
        return count == ids.length;
    }

    /**
     * Checks if the player has one (or more) of the given items equipped.
     *
     * @param items             The IDs of items to check for.
     * @return <tt>true</tt>    if the player has one (or more) of the given items
     *                          equipped; otherwise <tt>false</tt>.
     */
    public boolean containsOneOf(final int... items) {
        for (final RSItem item : getArray()) {
            for (final int id : items) {
                if (item.getID() == id) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * Returns a random double in the specified range with a Gaussian
     * distribution having a mean of the absolute value of the difference
     * between min and max and a standard deviation of 1.  The returned
     * value will honor the min and max boundaries.
     *
     * @param min   Minimum value (inclusive).
     * @param max   Maximum value (inclusive).
     * @return      The random <code>double</code> generated.
     */
    public double random(double min, double max) {
    	double mean = min + Math.abs(max-min)/2;

    	double next;
    	
    	// The loop ensures we honor the min/max values.
    	do  {
    		next = mean + random.nextGaussian();
    	} while (next<min || next>max);    	 
    	
        return next;
    }

    /**
     * Returns a random int in the specified range with a Gaussian
     * distribution having a mean of the absolute value of the difference
     * between min and max and a standard deviation of 1.  The returned
     * value will honor the min and max boundaries.
     *
     * @param min   Minimum value (inclusive).
     * @param max   Maximum value (inclusive).
     * @return      The random <code>int</code> generated.
     */
    public int random(int min, int max) {
    	int mean = min + Math.abs(max-min)/2;
    	int next;
    	
    	// The loop ensures we honor the min/max values.
    	do  {
    		next = (int) (mean + random.nextGaussian());
    	} while (next<min || next>max);    	 
    	
        return next;
    }

    /**
     * Returns a random int in the specified range with a Gaussian
     * distribution having a mean of the absolute value of the difference
     * between min and max and a standard deviation of sd.  The returned
     * value will honor the min and max boundaries.
     *
     * @param min   Minimum value (inclusive).
     * @param max   Maximum value (inclusive).
     * @return      The random <code>int</code> generated.
     */
    public int random(int min, int max, int sd) {
        int mean = min + Math.abs(max - min) / 2;
        int next;
        do {
        	next = (int) (mean + random.nextGaussian() * sd);
        } while (next < min || next > max);
        return next;
    }
}
